#include <nxos.h>

NX_PRIVATE void TEST_Map(void)
{
    void *addr;
    NX_Error err;
    addr = NX_MemMap(NX_NULL, 32, NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_Printf("1. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(addr, 32);

    addr = NX_MemMap(NX_NULL, 4096, NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_Printf("2. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(addr, 4096);

    addr = NX_MemMap(NX_NULL, 4096 * 10, NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_Printf("3. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(addr, 4096 * 10);

    addr = NX_MemMap(NX_NULL, 4096 * 100, NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_Printf("4. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(addr, 4096 * 100);

    addr = NX_MemMap(NX_NULL, 4096 * 1000, NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_Printf("5. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(addr, 4096 * 1000);

    addr = NX_MemMap((void *)0x1000, 4096 * 1000, NX_PROT_WRITE | NX_PROT_READ);
    err = NX_ErrorGet();
    NX_Printf("6. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    if (addr)
    {
        NX_MemZero(addr, 4096 * 1000);
    }

    addr = NX_MemMap((void *)0xFE000000, 4096 * 1000, NX_PROT_WRITE | NX_PROT_READ);
    err = NX_ErrorGet();
    NX_Printf("7. mmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));

    void *addr1 = NX_MemMap(NX_NULL, 4096 * 100, NX_PROT_WRITE | NX_PROT_READ);
    err = NX_ErrorGet();
    NX_Printf("8. mmap addr %p, err %d/%s\n", addr1, err, NX_ErrorToString(err));
    NX_MemSet(addr1, 0x5a, 4096 * 100);

    void *addr2 = NX_MemMap(NX_NULL, 4096 * 100, NX_PROT_WRITE | NX_PROT_READ);
    err = NX_ErrorGet();
    NX_Printf("9. mmap addr %p, err %d/%s\n", addr2, err, NX_ErrorToString(err));
    NX_MemCopy(addr2, addr1, 4096 * 100);
}

NX_PRIVATE void TEST_Unmap(void)
{
    void *addr;
    NX_Error err;

    err = NX_MemUnmap((void *)NX_NULL, 4096);
    NX_Printf("1. unmap addr %p, err %d/%s\n", NX_NULL, err, NX_ErrorToString(err));
    
    addr = (void *)0x1234;
    err = NX_MemUnmap((void *)addr, 0);
    NX_Printf("2. unmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    addr = NX_MemMap(NX_NULL, 512, NX_PROT_READ | NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_MemZero(addr, 512);
    err = NX_MemUnmap((void *)addr, 512);
    NX_Printf("3. unmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    addr = NX_MemMap(NX_NULL, 4096, NX_PROT_READ | NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_MemZero(addr, 4096);
    err = NX_MemUnmap((void *)addr, 4096);
    NX_Printf("4. unmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    addr = NX_MemMap(NX_NULL, 4096 * 10, NX_PROT_READ | NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_MemZero(addr, 4096 * 10);
    err = NX_MemUnmap((void *)addr, 4096 * 10);
    NX_Printf("5. unmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    addr = NX_MemMap(NX_NULL, 4096 * 100, NX_PROT_READ | NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_MemZero(addr, 4096 * 100);
    err = NX_MemUnmap((void *)addr, 4096 * 100);
    NX_Printf("6. unmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    addr = NX_MemMap(NX_NULL, 4096 * 1000, NX_PROT_READ | NX_PROT_WRITE);
    err = NX_ErrorGet();
    NX_MemZero(addr, 4096 * 1000);
    err = NX_MemUnmap((void *)addr, 4096 * 1000);
    NX_Printf("7. unmap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
}

NX_PRIVATE void TEST_Heap(void)
{
    void *addr;
    void *oaddr;

    NX_Error err;

    addr = NX_MemHeap(NX_NULL);
    err = NX_ErrorGet();
    NX_Printf("1. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));

    addr = NX_MemHeap(NX_NULL);
    err = NX_ErrorGet();
    NX_Printf("2. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    addr = NX_MemHeap((void *)0x1000);
    err = NX_ErrorGet();
    NX_Printf("2.1 heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));

    addr = NX_MemHeap((void *)0xF0000000);
    err = NX_ErrorGet();
    NX_Printf("2.2 heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));

    addr = NX_MemHeap(NX_NULL);
    err = NX_ErrorGet();
    NX_Printf("2.3 heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));

    oaddr = addr;
    NX_Printf("2.4 old addr %p, addr:%p\n", oaddr, addr);

    addr = NX_MemHeap((char *)addr + 128);
    err = NX_ErrorGet();
    NX_Printf("3. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_Printf("3.1 old addr %p\n", oaddr);
    NX_MemZero(oaddr, 128);
    
    oaddr = addr;
    NX_Printf("3.2 old addr %p\n", oaddr);

    addr = NX_MemHeap((char *)addr + 128);
    err = NX_ErrorGet();
    NX_Printf("4. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    
    NX_Printf("4.1 old addr %p\n", oaddr);
    NX_MemZero(oaddr, 128);
    
    oaddr = addr;
    NX_Printf("4.2 old addr %p\n", oaddr);

    addr = NX_MemHeap((char *)addr + 4096);
    err = NX_ErrorGet();

    NX_Printf("5. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));

    NX_Printf("5.1 old addr %p\n", oaddr);
    NX_MemSet(oaddr, 0x5a, 4096);
    
    oaddr = addr;
    addr = NX_MemHeap((char *)addr + 4096);
    err = NX_ErrorGet();
    NX_Printf("6. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(oaddr, 4096);
    
    oaddr = addr;
    addr = NX_MemHeap((char *)addr + 4096 * 10);
    NX_Printf("7. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(oaddr, 4096 * 10);
    
    oaddr = addr;
    addr = NX_MemHeap((char *)addr + 4096 * 100);
    err = NX_ErrorGet();
    NX_Printf("8. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(oaddr, 4096 * 100);
    
    oaddr = addr;
    addr = NX_MemHeap((char *)addr + 4096 * 1000);
    err = NX_ErrorGet();
    NX_Printf("9. heap addr %p, err %d/%s\n", addr, err, NX_ErrorToString(err));
    NX_MemZero(oaddr, 4096 * 1000);
}

NX_PRIVATE void TEST_Brk(void)
{
    void * p = NX_PosixSbrk(0);
    NX_Printf("cur: %p\n", p);
    p = NX_PosixSbrk(0x1000);
    NX_Printf("cur: %p\n", p);

    p = NX_PosixSbrk(0xa000);
    NX_Printf("cur: %p\n", p);

    p = NX_PosixSbrk(-0x1000);
    NX_Printf("cur: %p\n", p);
    p = NX_PosixSbrk(-0xa000);
    NX_Printf("cur: %p\n", p);
    p = NX_PosixSbrk(-0x1000);
    NX_Printf("cur: %p\n", p);
}

NX_PRIVATE void TEST_Malloc(void)
{
    char *buf[32];

    int i;
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc((i + 1) * 32);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);

        p = NX_MemReAlloc(p, (i + 1) * 32 * 2);
        NX_Printf("new p:%p\n", p);
        NX_MemZero(p, i);

        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(8);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(16);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(32);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(64);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(128);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(512);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(1024);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(4096);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(10000);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
    for (i = 0; i < 32; i++)
    {
        void * p = NX_MemAlloc(1000000);
        NX_Printf("p:%p\n", p);
        NX_MemZero(p, i);
        buf[i] = p;
    }
    for (i = 0; i < 32; i++)
    {
        NX_Printf("p:%p\n", buf[i]);
        NX_MemFree(buf[i]);
    }
}

NX_Error TEST_MemMan(char *cmdline)
{
    NX_Printf("mem man test\n");
    
    TEST_Map();
    TEST_Unmap();
    TEST_Heap();
    TEST_Brk();
    TEST_Malloc();
    
    return NX_EOK;
}
